package com.chatplus.application.common.util.enumeration;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class NameEnumUtils {

    /**
     * 获取带有名称的枚举 name 值
     *
     * @param value     枚举值
     * @param enumClass 枚举类型
     * @return name 值
     */
    public static String getName(String value, Class<? extends Enum<? extends NameEnum>> enumClass) {
        return getName(value, enumClass, false);
    }

    /**
     * 获取带有名称的枚举 name 值
     *
     * @param value          枚举值
     * @param enumClass      枚举类型
     * @param ignoreNotFound 如果找不到是否抛出异常, true:抛出，否则 false
     * @return name 值
     */
    public static String getName(String value, Class<? extends Enum<? extends NameEnum>> enumClass, boolean ignoreNotFound) {
        Enum<? extends NameEnum>[] values = enumClass.getEnumConstants();

        for (Enum<? extends NameEnum> anEnum : values) {
            NameEnum nameEnum = (NameEnum) anEnum;
            if (anEnum.name().equals(value)) {
                return nameEnum.getName();
            }
        }

        if (!ignoreNotFound) {
            String msg = enumClass.getName() + " 中找不到值为: " + value + " 的对应名称，" +
                enumClass.getName() + "信息为:" + castMap(enumClass);
            throw new IllegalArgumentException(msg);
        }

        return null;
    }

    /**
     * 将带有名称的枚举类转型为 map
     *
     * @param enumClass 带有名称的枚举
     * @return map， key 为枚举的 name，value 为枚举的 getName()
     */
    public static Map<String, Object> castMap(Class<? extends Enum<? extends NameEnum>> enumClass) {
        return castMap(enumClass, (String[]) null);
    }

    /**
     * 将带有名称的枚举类转型为 map
     *
     * @param enumClass 带有名称的枚举
     * @param ignore    要过滤的值（枚举的 name() 值）
     * @return map， key 为枚举的 name()，value 为枚举的 getName()
     */
    public static Map<String, Object> castMap(Class<? extends Enum<? extends NameEnum>> enumClass, String... ignore) {
        Map<String, Object> result = new LinkedHashMap<>();
        Enum<? extends NameEnum>[] values = enumClass.getEnumConstants();

        if (values == null || values.length == 0) {
            return result;
        }

        List<String> ignoreList = new ArrayList<>();

        if (ignore != null && ignore.length > 0) {
            ignoreList = Arrays.asList(ignore);
        }

        List<String> jsonIgnoreList = getJsonIgnoreList(enumClass);

        for (Enum<? extends NameEnum> o : values) {

            NameEnum ve = (NameEnum) o;

            if (jsonIgnoreList.contains(o.name())) {
                continue;
            }

            String value = ve.getName();

            if (ignoreList.contains(o.name())) {
                continue;
            }

            result.put(o.name(), value);
        }

        return result;
    }

    /**
     * 将值转型为枚举类
     *
     * @param value     枚举值
     * @param enumClass 带有名称的枚举
     * @param <T>       带有名称的枚举接口子类
     * @return 带有名称的枚举接口实现类
     */
    public static <T extends Enum<? extends NameEnum>> T parse(String value, Class<T> enumClass) {
        return parse(value, enumClass, false);
    }

    /**
     * 将值转型为枚举类
     *
     * @param value          枚举值
     * @param enumClass      带有名称的枚举
     * @param ignoreNotFound 如果找不到是否抛出异常, true:抛出，否则 false
     * @param <T>            带有名称的枚举接口子类
     * @return 带有名称的枚举接口实现类
     */
    @SuppressWarnings("unchecked")
    public static <T extends Enum<? extends NameEnum>> T parse(String value, Class<T> enumClass, boolean ignoreNotFound) {
        Enum<? extends NameEnum>[] values = enumClass.getEnumConstants();

        for (Enum<? extends NameEnum> o : values) {
            NameEnum nameEnum = (NameEnum) o;
            if (Objects.equals(nameEnum.getName(), value)) {
                return (T) o;
            }
        }

        if (!ignoreNotFound) {
            String msg = enumClass.getName() + " 中找不到值为: " + value + " 的对应名称，" +
                enumClass.getName() + "信息为:" + castMap(enumClass);
            throw new IllegalArgumentException(msg);
        }

        return null;
    }

    public static List<String> getJsonIgnoreList(Class<?> enumClass) {

        List<String> ignoreList = new ArrayList<>();

        JsonIgnoreProperties jsonIgnoreProperties = enumClass.getAnnotation(JsonIgnoreProperties.class);

        if (jsonIgnoreProperties != null) {
            ignoreList.addAll(Arrays.asList(jsonIgnoreProperties.value()));
        }

        Field[] fieldList = enumClass.getFields();

        for (Field field : fieldList) {
            JsonIgnore jsonIgnore = field.getAnnotation(JsonIgnore.class);
            if (jsonIgnore != null) {
                ignoreList.add(field.getName());
            }
        }

        return ignoreList;
    }

}
